﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Xml;

namespace SharpObjects.PathMapping
{
    public class DefaultPathMapper : IPathMapper
    {
        protected string configurationRootPath = null;

        #region IPathMapper Members

        public virtual string ConfigurationRootPath
        {
            get
            {
                if(this.configurationRootPath == null)
                {
                    this.configurationRootPath = GetExecutingAssemblyDirectory();

                    if (!this.configurationRootPath.EndsWith("\\"))
                    {
                        this.configurationRootPath += "\\";
                    }
                }

                return this.configurationRootPath;
            }
            set
            {
                this.configurationRootPath = value;

                if(!this.configurationRootPath.EndsWith("\\"))
                {
                    this.configurationRootPath += "\\";
                }
            }
        }

        public virtual string MapConfigurationFilePath(string path)
        {
            if (Path.IsPathRooted(path))
            {
                return path;
            }
            else
            {
                return ConfigurationRootPath + path;
            }

        }

        public virtual string MapApplicationDataPath(string path)
        {
            if(Path.IsPathRooted(path))
            {
                return path;
            }
            else
            {
                return GetApplicationDataDirectory(DefaultPathMapper.ApplicationName) + path;
            }

        }

        public virtual string MapApplicationDataPath(string root, string path)
        {
            if (Path.IsPathRooted(root))
            {
                if(Path.IsPathRooted(path))
                {
                    throw new ArgumentException("The 'path' argument must not contain rooted path");
                }

                if(!root.EndsWith("\\"))
                {
                    root += "\\";
                }

                return root + path;
            }
            else
            {
                string appDir = GetApplicationDataDirectory(root);
                return appDir + DefaultPathMapper.ApplicationName + "\\" + path;
            }

        }

        public virtual string MapApplicationBasePath(string path)
        {
            if (Path.IsPathRooted(path))
            {
                return path;
            }
            else
            {
                return GetAppBaseDirectory() + path;
            }
        }

        public virtual string MapAssemblyBasePath(string path)
        {
            if(Path.IsPathRooted(path))
            {
                return path;
            }
            else
            {
                return GetExecutingAssemblyDirectory() + path;
            }
        }

        public virtual string Resolve(string path)
        {
            string fullPath;

            fullPath = MapApplicationDataPath(path);

            if (!File.Exists(fullPath))
            {
                fullPath = MapApplicationBasePath(path);

                if (!File.Exists(fullPath))
                {
                    fullPath = MapAssemblyBasePath(path);

                    if (!File.Exists(fullPath))
                    {
                        throw new ArgumentException("Cannot resolve file path: " + path);
                    }
                }
            }

            return fullPath;
        }

        #endregion


        public static string GetAppBaseDirectory()
        {
            string appBase = AppDomain.CurrentDomain.GetData("APPBASE").ToString();

            if(!appBase.EndsWith("\\"))
            {
                appBase += "\\";
            }

            return appBase;
        }

        public static string GetExecutingAssemblyDirectory()
        {
            Assembly assembly = Assembly.GetExecutingAssembly();

            if (assembly == null)
            {
                throw new ApplicationException("Cannot determine executing assembly");
            }

            Uri codeBaseUri = new Uri(assembly.CodeBase);
            string dir = System.IO.Path.GetDirectoryName(codeBaseUri.LocalPath);

            if(!dir.EndsWith("\\"))
            {
                dir += "\\";
            }

            return dir;
        }

        public static string GetApplicationDataDirectory(string applicationName = null)
        {
            string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

            if(string.IsNullOrEmpty(path))
            {
                path = GetExecutingAssemblyDirectory();
            }

            if(!path.EndsWith("\\"))
            {
                path += "\\";
            }

            if(!string.IsNullOrEmpty(applicationName))
            {
                path += applicationName;

                if (!path.EndsWith("\\"))
                {
                    path += "\\";
                }
            }

            return path;
        }

        public static string ConfigFilePath
        {
            get
            {
                string configFilePath = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString();
                return configFilePath;
            }
        }

        public static bool IsWebApplication
        {
            get
            {
                return ConfigFilePath.ToLower().EndsWith("web.config");
            }
        }

        public static string ApplicationDirectoryName
        {
            get
            {
                string configFilePath = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString();
                
                DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(configFilePath));
                return di.Name;
            }
        }

        public static string ApplicationName
        {
            get
            {
                string configFilePath = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString();

                if(configFilePath.ToLower().EndsWith("web.config"))
                {
                    DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(configFilePath));
                    return di.Name;
                }
                else
                {
                    string name = Path.GetFileNameWithoutExtension(configFilePath);
                    
                    if(name.ToLower().EndsWith(".exe"))
                    {
                        name = name.Substring(0, name.Length - 4);
                    }

                    if(name.ToLower().EndsWith(".vshost"))
                    {
                        name = name.Substring(0, name.Length - 7);
                    }

                    return name;
                }
            }
        }


    }
}
